package com.vhuomai.wechat.controller;

import com.quanyue.auto.util.GlobalContext;
import com.quanyue.auto.util.ServiceResult;
import com.quanyue.auto.util.StringUtils;
import com.quanyue.auto.web.RequestContext;
import com.vhuomai.system.entity.BaseSysMerchant;
import com.vhuomai.system.service.MerchantService;
import com.vhuomai.wechat.entity.BaseWxAccount;
import com.vhuomai.wechat.service.WxAccountService;
import com.vhuomai.wechat.support.WxAware;
import com.vhuomai.weixin.common.bean.WxJsapiSignature;
import com.vhuomai.weixin.common.exception.WxErrorException;
import com.vhuomai.weixin.mp.api.WxMpMessageRouter;
import com.vhuomai.weixin.mp.api.WxMpService;
import com.vhuomai.weixin.mp.bean.message.WxMpXmlMessage;
import com.vhuomai.weixin.mp.bean.message.WxMpXmlOutMessage;
import com.vhuomai.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import com.vhuomai.weixin.mp.bean.result.WxMpUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * @author harris
 */
@Api(tags = "微信公众号")
@RestController
public class WxController {

    @Autowired
    private MerchantService merchantService;
    @Autowired
    private WxAccountService accountService;
    @Autowired
    private WxMpService wxMpService;
    @Autowired
    private WxMpMessageRouter router;
    @Autowired
    private WxAware wxAware;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @GetMapping(value = "/{fileName}.txt", produces = MediaType.TEXT_PLAIN_VALUE)
    public ResponseEntity<String> rootValidFile(@RequestHeader("host") String domain) {
        BaseSysMerchant merchant = merchantService.findByDomain(domain);
        if (merchant == null) {
            return ResponseEntity.notFound().build();
        }
        GlobalContext.setMerchantNo(merchant.getMerchantNo());
        BaseWxAccount account = accountService.findOne();
        return account == null ? ResponseEntity.notFound().build()
            : ResponseEntity.ok(account.getValidContent());
    }

    @GetMapping(value = "/wx/portal", produces = MediaType.TEXT_PLAIN_VALUE)
    public ResponseEntity<String> valid(@RequestParam("signature") String signature,
                                        @RequestParam("timestamp") String timestamp,
                                        @RequestParam("nonce") String nonce,
                                        @RequestParam("echostr") String echo,
                                        @RequestHeader("host") String domain) {
        this.logger.info("微信消息：[{}, {}, {}, {}]", signature, timestamp, nonce, echo);
        BaseSysMerchant merchant = merchantService.findByDomain(domain);
        if (merchant == null) {
            return ResponseEntity.notFound().build();
        }
        GlobalContext.setMerchantNo(merchant.getMerchantNo());
        if (StringUtils.isAnyBlank(signature, timestamp, nonce, echo)) {
            return ResponseEntity.badRequest().build();
        }
        if (this.wxMpService.checkSignature(timestamp, nonce, signature)) {
            return ResponseEntity.ok(echo);
        }
        return ResponseEntity.badRequest().build();
    }

    @PostMapping(value = "/wx/portal", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity<String> post(@RequestBody String requestBody,
                                       @RequestParam("signature") String signature,
                                       @RequestParam("timestamp") String timestamp,
                                       @RequestParam("nonce") String nonce,
                                       @RequestParam(name = "encrypt_type", required = false) String encType,
                                       @RequestParam(name = "msg_signature", required = false) String msgSignature,
                                       @RequestHeader("host") String domain) {
        this.logger.info("微信请求：[signature=[{}], encType=[{}], msgSignature=[{}], timestamp=[{}], nonce=[{}], requestBody=[{}] ",
            signature, encType, msgSignature, timestamp, nonce, requestBody);
        BaseSysMerchant merchant = merchantService.findByDomain(domain);
        if (merchant == null) {
            return ResponseEntity.notFound().build();
        }
        GlobalContext.setMerchantNo(merchant.getMerchantNo());
        if (!this.wxMpService.checkSignature(timestamp, nonce, signature)) {
            return ResponseEntity.badRequest().build();
        }

        String out = "";
        if (encType == null) {
            // 明文传输的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage != null) {
                out = outMessage.toXml();
            }
        } else if ("aes".equals(encType)) {
            // aes加密的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, this.wxMpService.getWxMpConfigStorage(),
                timestamp, nonce, msgSignature);
            logger.debug("消息解密后内容为：{} ", inMessage.toString());
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage != null) {
                out = outMessage.toEncryptedXml(this.wxMpService.getWxMpConfigStorage());
            }
        }
        this.logger.debug("组装回复信息：{}", out);
        return ResponseEntity.ok(out);
    }

    @GetMapping(value = "/wx/portal/auth/**")
    public ResponseEntity<String> auth(@RequestParam("code") String code,
                                       @RequestParam("state") String state,
                                       @RequestHeader("host") String domain,
                                       HttpServletRequest request,
                                       RequestContext context) throws IOException, WxErrorException, URISyntaxException {
        BaseSysMerchant merchant = merchantService.findByDomain(domain);
        if (merchant == null) {
            return ResponseEntity.notFound().build();
        }
        WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
        WxMpUser mpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, "zh_CN");
        wxAware.onLogin(state, mpUser, context);
        return ResponseEntity.created(new URI(wxAware.redirectUrl(request))).build();
    }

    @ApiOperation(value = "jsapi签名")
    @GetMapping(value = "/api/wx/jsapi/signature", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult<WxJsapiSignature> createSignature(@RequestParam("url") String url) throws WxErrorException {
        return ServiceResult.success(wxMpService.createJsapiSignature(url));
    }

    private WxMpXmlOutMessage route(WxMpXmlMessage message) {
        try {
            return this.router.route(message);
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
        }
        return null;
    }
}
